import { isNavigationFailure } from 'vue-router';
import NProgress from 'nprogress'; // progress bar
import { message as $message } from 'ant-design-vue';
import { REDIRECT_NAME } from './constant';
import type { WhiteNameList } from './constant';
import type { Router, RouteLocationNormalized } from 'vue-router';
import { useUserStore } from '@/store/modules/user';
import { useKeepAliveStore } from '@/store/modules/keepAlive';
import { ACCESS_TOKEN } from '@/enums/cacheEnum';
import { Storage } from '@/utils/Storage';
import { to as _to } from '@/utils/awaitTo';
import { isLogin } from '@/api/account/account';


NProgress.configure({ showSpinner: false }); // NProgress Configuration


export function createRouterGuards(router: Router, whiteNameList: WhiteNameList) {

  // 路由守卫
  router.beforeEach(async (to, _, next) => {
    NProgress.start(); // start progress bar
    const userStore = useUserStore();
    // 获取token
    const token = Storage.Get(ACCESS_TOKEN);
    // todo 前端校验token失效
    // console.log('token', token)
    // debugger
    if (token) {
      // 1. 判断是否登录
      const { data } = await isLogin()
      // console.log('是否登录', data)
      if(data == false) {
        userStore.setToken('');
        // 2. 未登录跳转到登录页面
        if (userStore.menus.length === 0) {
          // 加载默认路由
          _to(userStore.afterLogin());
        }
        next({ path: '/login' })
        return
      }
      // debugger
      // todo 加载动态枚举
      // 根据缓存的菜单判断是否生成过动态路由, 没有重新获取
      if (userStore.menus.length === 0) {
        // todo 登录成功获取动态路由菜单
        const [err] = await _to(userStore.afterLogin());
        // 动态路由生成失败
        if (err) {
          userStore.resetToken();
          console.error('动态路由生成失败', err)
          $message.error('系统菜单生成失败！请联系系统管理员');
        }
        // debugger
        next({ path: '/home' })
      } else {
        // debugger
        next();
      }
    } else {
      // debugger
      if(whiteNameList.some((n) => n === to.name)) {
        // 在免登录名单，直接进入
        next();
      } else {
        // 清除登录缓存信息
        Storage.clear()
        // 5. 未登录清空菜单, 和所有缓存的组件
        userStore.menus = []
        const keepAliveStore = useKeepAliveStore();
        keepAliveStore.clear();
        // 移除标签页
        localStorage.clear();
        // 6. 跳转到登录页面
        next({ path: '/login' });
      }
    }
  });

  /** 获取路由对应的组件名称 */
  const getComponentName = (route: RouteLocationNormalized) => {
    const comp = route.matched.at(-1)?.components?.default;
    return comp?.name ?? (comp as any)?.type?.name;
  };

  router.afterEach((to, from, failure) => {
    const keepAliveStore = useKeepAliveStore();
    const token = Storage.Get(ACCESS_TOKEN);

    if (isNavigationFailure(failure)) {
      console.error('failed navigation', failure);
    }
    // 在这里设置需要缓存的组件名称
    const toCompName = getComponentName(to);
    // 判断当前页面是否开启缓存，如果开启，则将当前页面的 componentName 信息存入 keep-alive 全局状态
    if (to.meta?.keepAlive) {
      // 需要缓存的组件
      if (toCompName) {
        keepAliveStore.add(toCompName);
      } else {
        console.warn(
          `${to.fullPath}页面组件的keepAlive为true但未设置组件名，会导致缓存失效，请检查`,
        );
      }
    } else {
      // 不需要缓存的组件
      if (toCompName) {
        keepAliveStore.remove(toCompName);
      }
    }
    // 如果进入的是 Redirect 页面，则也将离开页面的缓存清空(刷新页面的操作)
    if (to.name === REDIRECT_NAME) {
      const fromCompName = getComponentName(from);
      fromCompName && keepAliveStore.remove(fromCompName);
    }
    // 如果用户已登出，则清空所有缓存的组件
    if (!token) {
      keepAliveStore.clear();
    }
    NProgress.done(); // finish progress bar
  });

  router.onError((error) => {
    console.log(error, '路由错误');
  });
}
